package com.homedo.distributed.id.client.gen.command;

import com.homedo.common.util.http.HttpCommand;
import com.homedo.distributed.id.client.gen.buffer.GenBuffer;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


//@Component
//@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class GenCommand<R> extends HystrixCommand {

    private static final Logger _LOGGER = LoggerFactory.getLogger(HttpCommand.class);

    //尽量与retryCount保持一致
    private static final DynamicIntProperty DEFAULT_GEN_EXECUTIONTIMEOUTINMILLISECONDS = DynamicPropertyFactory.getInstance().getIntProperty("gen.hystrix.executionTimeoutInMilliseconds", 1000 * 600);//不执行超时策略
    private static final DynamicIntProperty DEFAULT_GEN_FALLBACKISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS = DynamicPropertyFactory.getInstance().getIntProperty("gen.hystrix.fallbackIsolationSemaphoreMaxConcurrentRequests", 1000000);
    private static final DynamicIntProperty DEFAULT_GEN_CIRCUITBREAKERERRORTHRESHOLDPERCENTAGE = DynamicPropertyFactory.getInstance().getIntProperty("gen.hystrix.circuitBreakerErrorThresholdPercentage", 99);

    private static final DynamicIntProperty DEFAULT_GEN_EXECUTIONISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS = DynamicPropertyFactory.getInstance().getIntProperty("gen.hystrix.executionIsolationSemaphoreMaxConcurrentRequests", 1000000);

    private String name;

    private GenBuffer<R> genBuffer;

    protected GenCommand(String groupKey, String name) {
        super(
                Setter
                        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
                        .andCommandKey(HystrixCommandKey.Factory.asKey(name))
                        .andCommandPropertiesDefaults(
                                HystrixCommandProperties.Setter()
                                        //这里使用信号量模式
                                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
                                        .withExecutionTimeoutInMilliseconds(DynamicPropertyFactory.getInstance().getIntProperty("hystrix.command." + name + ".execution.isolation.thread.timeoutInMilliseconds", DEFAULT_GEN_EXECUTIONTIMEOUTINMILLISECONDS.get()).get())
                                        .withFallbackIsolationSemaphoreMaxConcurrentRequests(DEFAULT_GEN_FALLBACKISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS.get())
                                        .withCircuitBreakerRequestVolumeThreshold(20)
//                                        .withCircuitBreakerSleepWindowInMilliseconds(5000)
                                        .withCircuitBreakerSleepWindowInMilliseconds(1)//不等待直接获取
                                        .withCircuitBreakerErrorThresholdPercentage(DynamicPropertyFactory.getInstance().getIntProperty("hystrix.command." + name + ".circuitBreaker.errorThresholdPercentage", DEFAULT_GEN_CIRCUITBREAKERERRORTHRESHOLDPERCENTAGE.get()).get())

                                        //使用信号量的时候 需要这个配置
                                        .withExecutionIsolationSemaphoreMaxConcurrentRequests(DEFAULT_GEN_EXECUTIONISOLATIONSEMAPHOREMAXCONCURRENTREQUESTS.get())
                        )
        );
        this.name = name;
    }

    @Override
    protected R run() throws Exception {
        return genBuffer.acquire();
    }

    @Override
    protected R getFallback() {
        Throwable exception = this.getExecutionException();
        String errorMsg = exception == null ? "" : exception.getMessage();
        return (R) (GenBuffer.DEFAULT_ERROR_ID + ":" + errorMsg);
    }

    @Override
    public String toString() {
        return "GenCommand{" +
                "name='" + name + '\'' +
                ", genBuffer=" + genBuffer.getClass().getName() +
                ", threadPoolKey=" + threadPoolKey +
                ", commandKey=" + commandKey +
                ", commandGroup=" + commandGroup +
                ", commandState=" + commandState +
                ", threadState=" + threadState +
                ", executionResult=" + executionResult +
                ", isResponseFromCache=" + isResponseFromCache +
                ", executionResultAtTimeOfCancellation=" + executionResultAtTimeOfCancellation +
                ", commandStartTimestamp=" + commandStartTimestamp +
                ", isCommandTimedOut=" + isCommandTimedOut +
                '}';
    }

    public void setGenBuffer(GenBuffer<R> genBuffer) {
        this.genBuffer = genBuffer;
    }
}
